
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.collision.CollisionResults;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;


public class Player implements ActionListener{
	
	CollisionShape playerShape;
	CharacterControl pControl;
	public Vector3f walkDirection;
	private boolean left, right, up, down;
	boolean isPhysical = false, freeFly = true;
	Vector3f startPosition = new Vector3f(6, 100, 6);
	String chunkPosition;
	int activeBlockType;
	
	public Player()
	{
		activeBlockType = BlockType.DIRT;
		walkDirection = new Vector3f();
		
		if(isPhysical)
			initPlayerPhysics();
		
		Engine.getEngine().getCamera().setLocation(startPosition);
	    Engine.getEngine().getCamera().lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
	    Engine.getEngine().getFlyByCamera().setMoveSpeed(50);
	    Engine.getEngine().getCamera().setFrustumPerspective(45, ((float)Engine.getEngine().getSettings().getWidth() / (float)Engine.getEngine().getSettings().getHeight()), .1f, 1000);
	    
	    initControls();
	}
	
	public void initPlayerPhysics()
	{			
		//Player Physics
		playerShape = new CapsuleCollisionShape(.4f, 1.2f);
		pControl = new CharacterControl(playerShape, .1f);
		pControl.setJumpSpeed(10);
	    pControl.setFallSpeed(30);
	    pControl.setGravity(30);
		pControl.setPhysicsLocation(startPosition);
		
		//Player model - currently obstructs the cameras view
		/*
		Box b = new Box(startPosition, 1, 1, 1);
		Geometry g = new Geometry("Box", b);
		Material mat = new Material(Engine.getEngine().getAssetManager(),"Common/MatDefs/Misc/Unshaded.j3md");
		g.setMaterial(mat);
		g.addControl(pControl);
		Engine.getEngine().getRootNode().attachChild(g);
		*/
		
		Engine.getEngine().getStateManager().getState(BulletAppState.class).getPhysicsSpace().add(pControl);
	}
	
	public void initControls()
	{
		Engine.getEngine().getInputManager().addMapping("Delete", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
		Engine.getEngine().getInputManager().addMapping("Add", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
		Engine.getEngine().getInputManager().addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
		Engine.getEngine().getInputManager().addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
		Engine.getEngine().getInputManager().addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
		Engine.getEngine().getInputManager().addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
		Engine.getEngine().getInputManager().addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
		Engine.getEngine().getInputManager().addListener(this, "Left");
		Engine.getEngine().getInputManager().addListener(this, "Right");
		Engine.getEngine().getInputManager().addListener(this, "Up");
		Engine.getEngine().getInputManager().addListener(this, "Down");
		Engine.getEngine().getInputManager().addListener(this, "Jump");
	    Engine.getEngine().getInputManager().addListener(this, "Delete");
	    Engine.getEngine().getInputManager().addListener(this, "Add");
	}
	
	public void onAction(String binding, boolean value, float tpf) {
		if (binding.equals("Left")) {
	      if (value) { left = true; } else { left = false; }
	    } else if (binding.equals("Right")) {
	      if (value) { right = true; } else { right = false; }
	    } else if (binding.equals("Up")) {
	      if (value) { up = true; } else { up = false; }
	    } else if (binding.equals("Down")) {
	      if (value) { down = true; } else { down = false; }
	    } else if (binding.equals("Jump")) {
	      pControl.jump();
	    }
	    else if(binding.equals("Delete") && !value)
		{
		  CollisionResults results = new CollisionResults();
		  Ray ray = new Ray(Engine.getEngine().getCamera().getLocation(), Engine.getEngine().getCamera().getDirection());
		  Engine.getEngine().getWorld().getWorldNode().collideWith(ray, results);
		  if(results.size() > 0)
		  {
			Geometry hit = results.getClosestCollision().getGeometry();
			int x = hit.getUserData("x");
			int y = hit.getUserData("y");
			int z = hit.getUserData("z");
			String chunk = hit.getUserData("chunk");
			
			Engine.getEngine().getWorld().getChunk(chunk).eraseBlock(x, y, z);
		  }
		  System.out.println(results.getClosestCollision().getGeometry().getName());
		}
		else if(binding.equals("Add") && !value)
		{
		  CollisionResults results = new CollisionResults();
		  Ray ray = new Ray(Engine.getEngine().getCamera().getLocation(), Engine.getEngine().getCamera().getDirection());
		  Engine.getEngine().getWorld().getWorldNode().collideWith(ray, results);
		  if(results.size() > 0)
		  {
			  Geometry hit = results.getClosestCollision().getGeometry();
			  int x = hit.getUserData("x");
			  int y = hit.getUserData("y");
			  int z = hit.getUserData("z");
			  String face = hit.getUserData("face");
			  String chunk = hit.getUserData("chunk");
			  
			  if(face.equals("north"))
			  {
				Engine.getEngine().getWorld().getChunk(chunk).chunk[x][y][z + 1] = activeBlockType;
				Renderer.drawBlock(Engine.getEngine().getWorld().getChunk(chunk), x, y, z + 1);
			  }
			  else if(face.equals("east"))
			  {
				Engine.getEngine().getWorld().getChunk(chunk).chunk[x - 1][y][z] = activeBlockType;
				Renderer.drawBlock(Engine.getEngine().getWorld().getChunk(chunk), x - 1, y, z);
			  }
			  else if(face.equals("south"))
			  {
				Engine.getEngine().getWorld().getChunk(chunk).chunk[x][y][z - 1] = activeBlockType;
				Renderer.drawBlock(Engine.getEngine().getWorld().getChunk(chunk), x, y, z - 1);
			  }
			  else if(face.equals("west"))
			  {
				Engine.getEngine().getWorld().getChunk(chunk).chunk[x + 1][y][z] = activeBlockType;
			  	Renderer.drawBlock(Engine.getEngine().getWorld().getChunk(chunk), x + 1, y, z);
			  }
			  else if(face.equals("top"))
			  {
				Engine.getEngine().getWorld().getChunk(chunk).chunk[x][y + 1][z] = activeBlockType;
				Renderer.drawBlock(Engine.getEngine().getWorld().getChunk(chunk), x, y + 1, z);
			  }
			  else if(face.equals("bottom"))
			  {
				Engine.getEngine().getWorld().getChunk(chunk).chunk[x][y - 1][z] = activeBlockType;
				Renderer.drawBlock(Engine.getEngine().getWorld().getChunk(chunk), x, y - 1, z);
			  }
			  
		  }
		}
	  }
	
	public Vector3f getWalkDirection()
	{
		return walkDirection;
	}
	
	public void update()
	{
		if(isPhysical && !freeFly)
		{
			Vector3f camDir = Engine.getEngine().getCamera().getDirection().clone().multLocal(0.2f);
		    Vector3f camLeft = Engine.getEngine().getCamera().getLeft().clone().multLocal(0.4f);
		    walkDirection.set(0, 0, 0);
		    if (left)  { walkDirection.addLocal(camLeft); }
		    if (right) { walkDirection.addLocal(camLeft.negate()); }
		    if (up)    { walkDirection.addLocal(camDir); }
		    if (down)  { walkDirection.addLocal(camDir.negate()); }
		    
		    pControl.setWalkDirection(walkDirection);
		    Engine.getEngine().getCamera().setLocation(pControl.getPhysicsLocation());
		}
	}

}
